package com.google.code.mircle.core.transfers;

import java.io.File;

import com.google.code.mircle.core.Worker;
import com.rasterbar.libtorrent.TorrentHandle;
import com.rasterbar.libtorrent.TorrentSession;
import com.rasterbar.libtorrent.TorrentSession.TorrentState;
import com.rasterbar.libtorrent.torrent_status;
import com.thoughtworks.xstream.annotations.XStreamAlias;

/**
 * @author axet
 * 
 */
public class TorrentDownload extends Worker {

    @XStreamAlias("TorrentDownloadState")
    static class State extends Worker.State {
        String source;
        File target;

        long downloadRate = 0;
        long count = 0;
        long total = -1;
        boolean done;
        File targetFile;
        Exception ee = null;
        String web;

        String title;

        TorrentState state;

        String status;
    }

    State state = new State();

    TorrentHandle torrent;

    TorrentSession lib;

    public TorrentDownload(String source, File target) {
        this.state.source = source.trim();
        this.state.target = target;
    }

    public TorrentDownload(String source, File target, String web) {
        this.state.source = source.trim();
        this.state.target = target;
        this.state.web = web.trim();
    }

    public TorrentDownload() {
    }

    @Override
    protected Worker.State getState() {
        return state;
    }

    @Override
    public void run() {
        synchronized (state) {
            if (state.downloadState == DownloadState.DOWNLOAD_COMPLETE && getTarget().exists()) {
                return;
            }

            load();
            torrent.resume();
        }

        try {
            while (true) {
                synchronized (state) {
                    state.count = 0;
                    state.ee = null;
                }

                while (!stop.get()) {
                    torrent_status st = torrent.status();

                    lib.check(st);

                    sync(st);

                    com.rasterbar.libtorrent.TorrentHandle.State ts = torrent.state();

                    changed();

                    if (ts == com.rasterbar.libtorrent.TorrentHandle.State.SEEDING) {
                        synchronized (state) {
                            state.state = lib.remove(torrent);
                        }
                        torrent = null;

                        synchronized (state) {
                            state.downloadState = DownloadState.DOWNLOAD_COMPLETE;
                        }
                    }

                    Thread.sleep(1000);
                }

                return;
            }
        } catch (RuntimeException e) {
            synchronized (state) {
                state.ee = e;
            }
        } catch (Exception e) {
            synchronized (state) {
                state.ee = e;
            }
        }
    }

    @Override
    public Status status() {
        synchronized (state) {
            return new Status(state.total, state.count, state.status, state.downloadRate, state.downloadRate);
        }
    }

    public File getTarget() {
        synchronized (state) {
            return state.targetFile;
        }
    }

    @Override
    public Worker.State save() {
        return state;
    }

    @Override
    public void load(Worker.State s) {
        state = (State) s;
    }

    @Override
    public String getSource() {
        synchronized (state) {
            return state.source;
        }
    }

    @Override
    public void stop() {
        super.stop();

        remove();
    }

    public void close() {
        super.close();

        remove();
    }

    void remove() {
        synchronized (state) {
            if (torrent != null) {
                state.state = lib.remove(torrent);
                torrent = null;
            }
        }
    }

    public TorrentHandle getHandle() {
        return torrent;
    }

    void load() {
        if (lib == null) {
            lib = TorrentSession.getInstance();
        }

        if (torrent == null) {
            if (state.state != null)
                torrent = lib.add(state.state, state.target);
            else
                torrent = lib.add(state.source, state.target);
        }
    }

    public void recheck() {
        if (torrent == null) {
            load();
        }
        torrent.recheck();
    }

    public void sync() {
        if (torrent == null)
            return;

        torrent_status st = torrent.status();
        sync(st);
    }

    void sync(torrent_status st) {
        synchronized (state) {
            state.total = st.total_wanted;
            state.count = st.total_wanted_done;
            state.downloadRate = (long) st.download_payload_rate;
            state.done = state.total == state.count;

            state.status = torrent.getInfo().name;
        }
    }

    public boolean checking() {
        synchronized (state) {
            if (torrent != null)
                return torrent.checking();
            else
                return false;
        }
    }

    public static boolean handle(String url) {
        if (url.contains("magnet"))
            return true;

        if (url.startsWith("http") && url.endsWith("torrent"))
            return true;

        if (url.startsWith("file") && url.endsWith("torrent"))
            return true;

        if (url.startsWith("/") && url.endsWith("torrent"))
            return true;

        return false;
    }

}
